#ifndef __SQLOPERATIONS_H
#define __SQLOPERATIONS_H

#include "Common.h"

#include "ace/Thread_Mutex.h"
#include "LockedQueue.h"
#include <queue>
#include "Utilities/Callback.h"

/// ---- BASE ---

class Database;
class SqlConnection;
class SqlDelayThread;

class SqlOperation
{
public:
    virtual void			OnRemove() { delete this; }
    virtual void			Execute(SqlConnection *conn) = 0;
    virtual					~SqlOperation() {}
};

/// ---- ASYNC STATEMENTS / TRANSACTIONS ----

class SqlStatement : public SqlOperation
{
private:
    const char *			m_sql;
public:
							SqlStatement(const char *sql) : m_sql(mangos_strdup(sql)){}
							~SqlStatement() { char* tofree = const_cast<char*>(m_sql); delete [] tofree; }
    void					Execute(SqlConnection *conn);
};

class SqlTransaction : public SqlOperation
{
private:
    std::vector<const char *> m_queue;

public:
							SqlTransaction() {}
							~SqlTransaction();

public:///
    void					DelayExecute(const char *sql)
    {
        char* _sql = mangos_strdup(sql);
        m_queue.push_back(_sql);
    }

    void					Execute(SqlConnection *conn);
};

/// ---- ASYNC QUERIES ----

class SqlQuery;                                             /// contains a single async query
class QueryResult;                                          /// the result of one
class SqlResultQueue;                                       /// queue for thread sync
class SqlQueryHolder;                                       /// groups several async quries
class SqlQueryHolderEx;                                     /// points to a holder, added to the delay thread

class SqlResultQueue : public ACE_Based::LockedQueue<MaNGOS::IQueryCallback* , ACE_Thread_Mutex>
{
public:
    SqlResultQueue() {}
    void Update();
};

class SqlQuery : public SqlOperation
{
private:
    const char *m_sql;
    MaNGOS::IQueryCallback * m_callback;
    SqlResultQueue * m_queue;
public:
    SqlQuery(const char *sql, MaNGOS::IQueryCallback * callback, SqlResultQueue * queue)
        : m_sql(mangos_strdup(sql)), m_callback(callback), m_queue(queue) {}
    ~SqlQuery() { char* tofree = const_cast<char*>(m_sql); delete [] tofree; }
    void Execute(SqlConnection *conn);
};

class SqlQueryHolder
{
friend class SqlQueryHolderEx;

public:// c&D
							SqlQueryHolder() {}
							~SqlQueryHolder();
public://
    bool					SetQuery(size_t index, const char *sql);
    bool					SetPQuery(size_t index, const char *format, ...) ATTR_PRINTF(3,4);
    void					SetSize(size_t size);
    QueryResult*			GetResult(size_t index);
    void					SetResult(size_t index, QueryResult *result);
    bool					Execute(MaNGOS::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue);

private:
	typedef std::pair<const char*, QueryResult*> SqlResultPair;
	std::vector<SqlResultPair> m_queries;
};

class SqlQueryHolderEx : public SqlOperation
{
public:///inherit virutals
	void					Execute(SqlConnection *conn);
public:
							SqlQueryHolderEx(SqlQueryHolder *holder, MaNGOS::IQueryCallback * callback, SqlResultQueue * queue)
								: m_holder(holder), m_callback(callback), m_queue(queue) {}

private:
	SqlQueryHolder *		m_holder;
	MaNGOS::IQueryCallback * m_callback;
	SqlResultQueue *		m_queue;

};
#endif                                                      //__SQLOPERATIONS_H
